/*
 * File:        packetAssembler.h
 * Authors:     Jonathan Kotker (ee122-bw) and Shaan Mulchandani (ee122-bv)
 * Description: This header file contains the methods required to assemble
 *              a message into a packet to be sent across the network.
 */

#ifndef _PACKETASSEMBLER_H
#define	_PACKETASSEMBLER_H

#include "packetContents.h"

/*
 * Sets the HP/EXP into the provided packet bytes starting at position `x'.
 */
void set_hp_exp(signed long int hpExp, char* packetbytes, int x) {
    int intermed = 0;
    intermed = (hpExp & 0xF000) >> 12;
    packetbytes[x] = (char) intermed;

    intermed = 0;
    intermed = (hpExp & 0x0F00) >> 8;
    packetbytes[x + 1] = (char) intermed;

    intermed = 0;
    intermed = (hpExp & 0x00F0) >> 4;
    packetbytes[x + 2] = (char) intermed;

    intermed = 0;
    intermed = (hpExp & 0x000F);
    packetbytes[x + 3] = (char) intermed;
};

/*
 * This utility function assembles a message into a packet
 * to be sent across the network.
 * 
 * `arr' is a pointer to the byte array containing the information
 * to be sent as a packet. `content' is a pointer to a struct
 * containing the data to be used to fill the byte array. The
 * method returns the length of the array to be sent out as
 * the packet.
 */
int assemblePacket(char* arr, packetContents* content) {
    switch (content->messageType) {
        case LOGIN_REQUEST:
        {
            int i;
            for (i = 0; i < 16; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x10;
            arr[3] = LOGIN_REQUEST;

            for (i = 0; i < 9; i++) {
                if (content->victimName[i] == 0x00)
                    break;
                arr[i + 4] = content->victimName[i];
            }

            return 16;
        }

        case LOGIN_REPLY:
        {
            int i;
            for (i = 0; i < 16; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x10;
            arr[3] = LOGIN_REPLY;
            arr[4] = content->errorCode;

            signed long int hp = content->hp;
            set_hp_exp(hp, arr, 5);

            signed long int exp = content->exp;
            set_hp_exp(exp, arr, 9);

            arr[13] = content->xLoc;
            arr[14] = content->yLoc;
            arr[15] = 0x00;

            return 16;
        }

        case MOVE:
        {
            int i;
            for (i = 0; i < 8; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x08;
            arr[3] = MOVE;
            arr[4] = content->moveDir;

            return 8;
        }

        case MOVE_NOTIFY:
        {
            int i;
            for (i = 0; i < 24; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x18;
            arr[3] = MOVE_NOTIFY;
            
            for (i = 0; i < 9; i++) {
                if (content->victimName[i] == 0x00)
                    break;
                arr[i + 4] = content->victimName[i];
            }

            arr[14] = content->xLoc;
            arr[15] = content->yLoc;

            signed long int hp = content->hp;
            set_hp_exp(hp, arr, 16);

            signed long int exp = content->exp;
            set_hp_exp(exp, arr, 20);

            return 24;
        }

        case ATTACK:
        {
            int i;
            for (i = 0; i < 16; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x10;
            arr[3] = ATTACK;

            for (i = 0; i < 9; i++) {
                if (content->victimName[i] == 0x00)
                    break;
                arr[i + 4] = content->victimName[i];
            }

            return 16;
        }

        case ATTACK_NOTIFY:
        {
            int i;
            for (i = 0; i < 32; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x20;
            arr[3] = ATTACK_NOTIFY;

            for (i = 0; i < 9; i++) {
                if (content->attackerName[i] == 0x00)
                    break;
                arr[i + 4] = content->attackerName[i];
            }

            for (i = 0; i < 9; i++) {
                if (content->victimName[i] == 0x00)
                    break;
                arr[i + 14] = content->victimName[i];
            }

            arr[24] = content->damage;

            signed long int hp = content->hp;
            set_hp_exp(hp, arr, 25);
            
            return 32;
        }

        case SPEAK_NOTIFY:
        {
            int i;
            for (i = 0; i < MAX_RECV_LEN; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[3] = SPEAK_NOTIFY;

            for (i = 0; i < 9; i++) {
                if (content->victimName[i] == 0x00)
                    break;
                arr[i + 4] = content->victimName[i];
            }

            int count = 14;

            for (i = 0; i < EE122_MAX_MSG_LENGTH; i++) {
                if (content->message[i] == 0x00) {
                    count++;
                    break;
                }

                arr[i + 14] = content->message[i];
                count++;
            }

            if (count % 4 > 0) {
                count = count / 4;
                count++;
                count = count * 4;
            }

            arr[1] = (count & 0xFF00) >> 8;
            arr[2] = count & 0xFF;

            return count;
        }
        
        case SPEAK:
        {
            int count = 4;

            int i;
            for (i = 0; i < MAX_SEND_LEN; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[3] = SPEAK;

            for (i = 0; i < EE122_MAX_MSG_LENGTH; i++) {
                if (content->message[i] == 0x00) {
                    count++;
                    break;
                }

                arr[i + 4] = content->message[i];
                count++;
            }

            if (count % 4 > 0) {
                count = count / 4;
                count++;
                count = count * 4;
            }

            arr[1] = (count & 0xFF00) >> 8;
            arr[2] = count & 0xFF;

            return count;
        }

        case LOGOUT:
        {
            int i;
            for (i = 0; i < 4; i++)
                arr[i] = 0x00;
            
            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x04;
            arr[3] = LOGOUT;

            return 4;
        }

        case LOGOUT_NOTIFY:
        {
            int i;
            for (i = 0; i < 16; i++)
                arr[i] = 0x00;
            
            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x10;
            arr[3] = LOGOUT_NOTIFY;

            for (i = 0; i < 9; i++) {
                if (content->victimName[i] == 0x00)
                    break;
                arr[i + 4] = content->victimName[i];
            }

            return 16;
        }

        case INVALID_STATE:
        {
            int i;
            for (i = 0; i < 8; i++)
                arr[i] = 0x00;

            arr[0] = EE122_VALID_VERSION;
            arr[1] = 0x00;
            arr[2] = 0x08;
            arr[3] = INVALID_STATE;
            arr[4] = content->errorCode;

            return 8;
        }
    }
};

#endif  /* _PACKETASSEMBLER_H_ */
